import datetime
import os

import pickle
from enum import Enum
from typing import List, Dict


class SaveType(Enum):
    """保存类型枚举"""
    ExcelAnalysis = 1
    Setting = 2


class FieldType(Enum):
    """字段类型"""
    Unknow = ""
    Integer = "int"
    Long = "long"
    String = "str"
    Float = "float"
    Double = "double"
    Boolean = "bool"


class IndexType(Enum):
    """索引方式(生成代码用)"""
    NULL = ""
    """无对应"""
    List = "list"
    """纯列表"""
    Map = "map"
    """字典"""
    Map2List = "map2list"
    """字典索引结果为列表集合"""
    MultKeyMap = "mkMap"
    """多键值字典"""

    def parseFromValue(value: str):
        if value.strip(" ") == IndexType.List.value:
            return IndexType.List
        if value.strip(" ") == IndexType.Map.value:
            return IndexType.Map
        if value.strip(" ") == IndexType.Map2List.value:
            return IndexType.Map2List
        if value.strip(" ") == IndexType.MultKeyMap.value:
            return IndexType.MultKeyMap
        return IndexType.NULL


class Platform(Enum):
    """索引方式(生成代码用)"""
    NULL = ""
    """无对应"""
    Java = "java"
    """Java代码读取"""
    Laya = "laya"
    """Laya代码读取"""
    Unity3d = "u3d"
    """Unity3d代码读取"""

    def parseFromValue(value: str):
        if value.strip(" ") == Platform.Java.value:
            return Platform.Java
        if value.strip(" ") == Platform.Laya.value:
            return Platform.Laya
        if value.strip(" ") == Platform.Unity3d.value:
            return Platform.Unity3d
        return Platform.NULL


class SettingData:
    """配置页数据保存"""
    groupPrefix: str = "group_"
    """组常量标识字头"""
    libTablePrefix: str = "TB_"
    """单标常量标识字头"""


    readerCfgSheetName: str = None
    """配置页Sheet名"""
    readerCfgTagImportSheets: str = None
    """TAG-导入表名"""
    readerCfgIgnoreColumn: str = None
    """不导出标识"""

    defDirExcelFile: str = None
    """Excel默认目录"""
    defDirJsonFile: str = None
    """导出Json目录"""
    defDefineJsonFile: str = None
    """主定义Json文件名"""
    defDirJavaFile: str = None
    """Java代码目录"""
    defDirLayaFile: str = None
    """Laya代码目录"""
    defDirUnityFile: str = None
    """Unity代码目录"""

    genLibConstantClass: str = None
    """Lib生成常量表类名"""
    genLibEasyAccessClass: str = None
    """Lib简易读取类类名"""
    genLibPrefix: str = None
    """Lib实体类字头"""

    def resetDefault(self, force: bool):
        if force or self.readerCfgSheetName is None:
            self.readerCfgSheetName = "CFG"
        if force or self.readerCfgTagImportSheets is None:
            self.readerCfgTagImportSheets = "导入表名"
        if force or self.readerCfgIgnoreColumn is None:
            self.readerCfgIgnoreColumn = "不导,不导出,跳过,skip,ignore"
        if force or self.defDirExcelFile is None:
            self.defDirExcelFile = "excel\\"
        if force or self.defDirJsonFile is None:
            self.defDirJsonFile = "output\\"
        if force or self.defDefineJsonFile is None:
            self.defDefineJsonFile = "_definition.json"
        if force or self.defDirJavaFile is None:
            self.defDirJavaFile = "java\\"
        if force or self.defDirLayaFile is None:
            self.defDirLayaFile = "laya\\"
        if force or self.defDirUnityFile is None:
            self.defDirUnityFile = "unity\\"

        if force or self.genLibConstantClass is None:
            self.genLibConstantClass = "ExcelLibConstant"
        if force or self.genLibEasyAccessClass is None:
            self.genLibEasyAccessClass = "ExcelLibDataEasyAccess"
        if force or self.genLibPrefix is None:
            self.genLibPrefix = "Lib"

class Union:
    """关联配置"""
    myKey: str
    """本表键名"""
    unionTableName: str
    """关联表的Sheet名"""
    unionKey: str
    """关联表对应的键名(类型必须与myKey所指字段一致)"""

    def parseFromValue(value: str):
        arr = value.split("=")
        if len(arr) != 2:
            return None
        myKey = arr[0].strip(" ")
        if len(myKey) < 1:
            return None
        arr2 = arr[1].split(".")
        if len(arr2) != 2:
            return None
        table = arr2[0].strip(" ")
        key = arr2[1].strip(" ")
        if len(table) < 1 or len(key) < 1:
            return None
        union: Union = Union()
        union.myKey = myKey
        union.unionTableName = table
        union.unionKey = key
        return union


class FieldData:
    """字段数据"""
    colunmOrd: int = -1
    fieldName: str = ""
    fieldType: FieldType = FieldType.Unknow
    fieldKey: str = ""
    fieldRestrain: str = ""
    canNotEmpty: bool = False
    isMainKey: bool = False

class LoadConfig:
    """代码加载配置"""
    type: IndexType
    """索引类型"""
    keyFields: List[FieldData]
    keyFieldStrings: List[str]
    """多键值字段键名"""
    exportPlatforms: Dict[str, Platform] = dict()
    """导出平台列表。枚举:Platform[] \n检测是否存在使用Platform.Java in platforms.values()"""
    unions: List[Union] = []
    """关联配置。类：Union[]"""
    loadWeight: int = 0
    """加载先后权重"""
    group: str = ""
    """加载组别"""
    loadRelations: List[str] = []
    """关联加载(表json名)"""

    def getDataFullName(self, table):
        """代码中识别用的名字, 带索引类型名，带索引字段名"""
        key: str = ""
        for kf in self.keyFields:
            ss = list(kf.fieldKey)
            ss[0] = ss[0].upper()
            key += "".join(ss)
        if self.type is IndexType.Map:
            return table.jsonName + "MapBy" + key
        elif self.type is IndexType.List:
            return table.jsonName + "List"
        elif self.type is IndexType.MultKeyMap:
            return table.jsonName + "MkMapBy" + key
        elif self.type is IndexType.Map2List:
            return table.jsonName + "MapListBy" + key

    def getDataName(self, table):
        """代码中识别用的名字, 带索引类型名"""
        if self.type is IndexType.Map:
            return table.jsonName + "Map"
        elif self.type is IndexType.List:
            return table.jsonName + "List"
        elif self.type is IndexType.MultKeyMap:
            return table.jsonName + "MkMap"
        elif self.type is IndexType.Map2List:
            return table.jsonName + "MapList"

    def getConstantDataFullName(self, table):
        """代码中识别用的名字, 带索引类型名，带索引字段名"""
        key: str = ""
        for kf in self.keyFields:
            key += kf.fieldKey + "_"
        if self.type is IndexType.Map:
            return table.jsonName.upper() + "_MAP_" + key.upper()
        elif self.type is IndexType.List:
            return table.jsonName.upper() + "_LIST_"
        elif self.type is IndexType.MultKeyMap:
            return table.jsonName.upper() + "_MKMAP_" + key.upper()
        elif self.type is IndexType.Map2List:
            return table.jsonName.upper() + "_MAPLIST_" + key.upper()



class TableData:
    """Excel表格数据"""
    fields: List[FieldData] = []
    """字段数据"""
    sheetName: str = ""
    """Sheet标签名"""
    jsonName: str = ""
    """导出json文件名(不含.json)"""
    loadConfigs: List[LoadConfig] = []
    """索引配置，LoadConfig[]"""
    fieldNameRowIndex: int = -1;
    """字段中文名在第几行"""
    fieldKeyRowIndex: int = -1;
    """字段名在第几行"""
    fieldTypeRowIndex: int = -1;
    """字段类型在第几行"""
    fieldRestrainRowIndex: int = -1;
    """字段约束在第几行"""
    fieldDataRowIndex: int = -1;
    """正式数据起始在第几行"""
    isListChecked: bool = False;
    """是否被勾选（根据勾选同步）"""
    lastExecuteTime: datetime = None
    """最后一次操作时间"""

    def getClassname(self):
        """获取生成代码的类名"""
        edata:EData = EData()
        className: str = self.jsonName
        classNameUpper = list(className)
        classNameUpper[0] = classNameUpper[0].upper()
        className = edata.setting.genLibPrefix + "".join(classNameUpper)
        return className



class ExcelData:
    """Excel文件数据"""
    tables: Dict[str, TableData]
    """Sheet表，key使用导出json名"""
    fileName: str = ""
    filePath: str = ""

    def __init__(self):
        tables = dict()


class EData():
    """数据持久化(单例)"""

    DEFAULT_SAVE_DATA_EXCEL_ANALYSIS = "Excel2JsonData.data"
    DEFAULT_SAVE_DATA_EXCEL_SETTING = "Excel2JsonSetting.data"
    # DEFAULT_SAVE_TABLE_FILE = "Excel2JsonTable.data"

    excelDatas: Dict[str, ExcelData]
    """excel解析保存"""
    setting: SettingData
    """settingData"""

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls, *args, **kwargs)
            print("第一次创建EData")
            cls.excelDatas = dict()
            cls.setting = SettingData()
        return cls._instance

    def restoreFromFile(self):
        self.load(SaveType.ExcelAnalysis, SaveType.Setting)  # 打开程序时尝试恢复之前软件状态，读取Excel2JsonData.data文件
        self.setting.resetDefault(False) #每次打开时检测配置数据有没有None的，有none则补充为默认值

    def clear(self):
        self.excelDatas = dict()

    def save(self, *saveTypes):
        """保存当前数据
           save(SaveType1,SaveType2..) -> bool
        """
        for type in saveTypes:
            print("SAVE:" + type.name)
            if type is SaveType.ExcelAnalysis:
                f = open(self.DEFAULT_SAVE_DATA_EXCEL_ANALYSIS, "wb")
                pickle.dump(self.excelDatas, f)
                f.close()
            if type is SaveType.Setting:
                f = open(self.DEFAULT_SAVE_DATA_EXCEL_SETTING, "wb")
                pickle.dump(self.setting, f)
                f.close()
        return True

    def load(self, *saveTypes):
        """读取数据
           load(SaveType1,SaveType2..) -> bool
        """
        for type in saveTypes:
            print("LOAD:" + type.name)
            if type is SaveType.ExcelAnalysis:
                if not os.path.isfile(self.DEFAULT_SAVE_DATA_EXCEL_ANALYSIS):
                    return False
                f = open(self.DEFAULT_SAVE_DATA_EXCEL_ANALYSIS, "rb")
                self.excelDatas = pickle.load(f)
                f.close()
            if type is SaveType.Setting:
                if not os.path.isfile(self.DEFAULT_SAVE_DATA_EXCEL_SETTING):
                    return False
                f = open(self.DEFAULT_SAVE_DATA_EXCEL_SETTING, "rb")
                self.setting = pickle.load(f)
                f.close()

        return True
